package RAM(RAM, RAMclient, RAMreq(..)) where
import ClientServer

--@ \subsubsection{\te{RAM} and \te{TRAM}}
--@ \index{RAM@\te{RAM} (package)|textbf}
--@
--@ The \te{RAM} type is used for various types of memories.
--@ The memory is a \te{Server} which accepts read or write requests.
--@ A read request will generate a response containing the read data.
--@ The latency for a \te{RAM} is arbitrary, it does not even have to
--@ be a fixed latency.
--@
--@ Note, the types of the address and data are arbitrary.

--@ \index{RAM@\te{RAM} (type)|textbf}
--@ \begin{libverbatim}
--@ typedef Server#(RAMreq#(adr, dta), dta) RAM #(type adr, type dta);
--@ \end{libverbatim}
type RAM adr dta = Server (RAMreq adr dta) dta

--@ \index{RAMclient@\te{RAMclient} (type)|textbf}
--@ \begin{libverbatim}
--@ typedef Client#(RAMreq#(adr, dta), dta) RAMclient #(type adr, type dta);
--@ \end{libverbatim}
type RAMclient adr dta = Client (RAMreq adr dta) dta

--@ \index{RAMreq@\te{RAMreq} (type)|textbf}
--@ \begin{libverbatim}
--@ typedef union tagged {
--@     adr Read;
--@     Tuple2#(adr, dta) Write;
--@ } RAMreq #(type adr, type dta) deriving (Eq, Bits);
--@ \end{libverbatim}
data RAMreq adr dta
        = Read      adr
        | Write (adr, dta)
    deriving (Eq)

instance (Bits adr sa, Bits dta sd, Add sa sd sz1, Add sz1 1 sz) =>
         Bits (RAMreq adr dta) sz where
  pack (Read adr) = (0 :: Bit 1) ++ (pack adr) ++ _
  pack (Write (adr, dta)) = (1 :: Bit 1) ++ (pack adr) ++ (pack dta)
  unpack bits = let (first, rest) = (split bits) :: (Bit 1, Bit sz1)
                    (adr, dta) = (split rest) :: (Bit sa, Bit sd)
                in if (first == (0 :: Bit 1)) then
                     Read (unpack adr)
                   else Write (unpack adr, unpack dta)
